<?php
/********************************************************************
 *	Author:
 *		Jestery Liu <jestery@gmail.com>
 *		http://www.pte.cn
 *
 *	File:			Dispatcher.class.php
 *	Create Date:	2007-05-23 17:00:25 CST
 *******************************************************************/
require_once(PTE::getCoreLibsPath().'Request.class.php');
require_once(PTE::getCoreLibsPath().'Response.class.php');
require_once(PTE::getCoreLibsPath().'Module.class.php');
require_once(PTE::getCoreLibsPath().'Event.class.php');

class Dispatcher
{
	/**
	 * Request object
	 *
	 * @var HttpRequest
	 */
	private $request;
	/**
	 * Response Object
	 *
	 * @var HttpResponse
	 */
	private $response;
	/**
	 * UrlMapper Object
	 *
	 * @var UrlMapper
	 */
	private $urlmapper;
	private $nextAction;
	private $returnResponse = false;
	
	public function __construct($urlMapper)
	{
		$this->urlmapper = $urlMapper;
		$this->setRequest(Request::getInstance());
		$this->setResponse(Response::getInstance());
	}

	public function setRequest($req)
	{
		$this->request = $req;
	}
	public function getRequest()
	{
		return $this->request;
	}
	public function setResponse($response)
	{
		$this->response = $response;
	}
	public function getResponse()
	{
		return $this->response;
	}
	public function setNextAction($actionName, array $params = array())
	{
		$this->nextAction = $actionName;
		foreach ($params as $key=>$value)
		{
			$this->request->setParam($key, $value);
		}
		list($app, $mod, $act) = explode('.', $actionName);
		$this->request->setApplicationName($app);
		$this->request->setModuleName($mod);
		$this->request->setActionName($act);
		$this->request->setDispatched(false);
	}
	public function dispatch()
	{
		do
		{
			$this->request->setDispatched(true);
			Event::notifyEvent($this, 'preDispatch', array('request'=>&$this->request, 'response'=>&$this->response, 'urlMapper'=>&$this->urlmapper));
			if (!$this->nextAction) {
				if ($this->urlmapper->map()===false)
				{
					throw new Exception('Unable to dispatch. No default action specified.');
				}
			}
			unset($this->nextAction);
			$app = $this->request->getApplicationName();
			$mod = $this->request->getModuleName();
			$act = $this->request->getActionName();
			$modClass = PTE::getModuleClassName($mod);
			$actMethod = PTE::getActionMethodName($act);
			Loader::loadModule($app.'.'.$mod);
			if (!class_exists($modClass, false))
			{
				throw new Exception("Unable to find module class \"$modClass\"");
			}
			$module = new $modClass();
			if (!method_exists($module, $actMethod) || !method_exists($module, 'setDispatcher'))
			{
				throw new Exception("Unable to find action \"{$modClass}->{$actMethod}()\" or setDispatcher() not impliemented");
			}
			$module->setDispatcher($this);
			$module->setRequest($this->request);
			$module->setResponse($this->response);
			Event::notifyEvent($this, 'onDispatch', array('request'=>&$this->request, 'response'=>&$this->response, 'urlMapper'=>&$this->urlmapper, 'module'=>&$module, 'action'=>$actMethod));
			$module->$actMethod();
			Event::notifyEvent($this, 'postDispatch', array('request'=>&$this->request, 'response'=>&$this->response, 'urlMapper'=>&$this->urlmapper));
		} while (!$this->request->isDispatched());
		if (!$this->returnResponse) {
			$this->response->send();
		} else {
			return $this->response;
		}
		Event::notifyEvent($this, 'endDispatch', array('request'=>&$this->request, 'response'=>&$this->response, 'urlMapper'=>&$this->urlmapper));
	}
}